package com.atguigu.gulimall.cart.Service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.TypeReference;
import com.atguigu.common.utils.R;
import com.atguigu.common.vo.SkuInfoVo;
import com.atguigu.gulimall.cart.Service.CartService;
import com.atguigu.gulimall.cart.feign.ProductFeignService;
import com.atguigu.gulimall.cart.interceptor.CartInterceptor;
import com.atguigu.gulimall.cart.vo.Cart;
import com.atguigu.gulimall.cart.vo.CartItem;
import com.atguigu.gulimall.cart.vo.UserInfoTo;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.BoundHashOperations;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.stream.Collectors;

/**
 * @description:
 * @author: BlueSky
 * @create: 2021-09-26 10:48
 **/
@Service
public class CartServiceImpl implements CartService {

	@Autowired
	StringRedisTemplate redisTemplate;

	@Autowired
	ProductFeignService productFeignService;

	@Autowired
	ThreadPoolExecutor executor;

	private final String CART_PREFIX = "gulimall:cart:";

	@Override
	public CartItem addToCart(Long skuId, Integer num) throws ExecutionException, InterruptedException {
		BoundHashOperations<String, Object, Object> cartOps = getCartOps();

		String res = (String) cartOps.get(skuId.toString());
		if (StringUtils.isEmpty(res)){
			CartItem cartItem = new CartItem();
			//购物车无此商品
			//商品添加到购物车
			//1、远程查询当前要添加的商品信息
			CompletableFuture<Void> getSkuInfoTask = CompletableFuture.runAsync(() -> {
				R skuInfo = productFeignService.getSkuInfo(skuId);
				SkuInfoVo data = skuInfo.getData("skuInfo", new TypeReference<SkuInfoVo>() {
				});

				cartItem.setCheck(true);
				cartItem.setCount(num);
				cartItem.setImage(data.getSkuDefaultImg());
				cartItem.setTitle(data.getSkuTitle());
				cartItem.setSkuId(skuId);
				cartItem.setPrice(data.getPrice());
			}, executor);

			//2、远程查询sku的组合信息
			CompletableFuture<Void> getSkuSaleAttrValues = CompletableFuture.runAsync(() -> {
				List<String> skuSaleAttrValues = productFeignService.getSkuSaleAttrValues(skuId);
				cartItem.setSkuAttr(skuSaleAttrValues);
			}, executor);

			CompletableFuture.allOf(getSkuInfoTask,getSkuSaleAttrValues).get();
			String s = JSON.toJSONString(cartItem);
			cartOps.put(skuId.toString(),s);

			return cartItem;
		}else {
			//购物车有此商品，修改数量
			CartItem cartItem = JSON.parseObject(res, CartItem.class);
			cartItem.setCount(cartItem.getCount()+num);

			cartOps.put(skuId.toString(),JSON.toJSONString(cartItem));
			return cartItem;
		}
	}

	//添加购物车后重定向至新页面变更为查询操作
	@Override
	public CartItem getCartItem(Long skuId) {
		BoundHashOperations<String, Object, Object> cartOps = getCartOps();
		String str = (String) cartOps.get(skuId.toString());  //取出来为json，需转为可用类型
		CartItem cartItem = JSON.parseObject(str, CartItem.class);
		return cartItem;
	}

	@Override
	public Cart getCart() throws ExecutionException, InterruptedException {
		Cart cart = new Cart();
		UserInfoTo userInfoTo = CartInterceptor.threadLocal.get();
		if (userInfoTo.getUserId()!=null){
			//1、登录
			String cartKey = CART_PREFIX + userInfoTo.getUserKey();
			// 2、如果临时购物车的数据还没有进行合并【合并购物车】
			List<CartItem> tempCartItems = getCartItems(CART_PREFIX + userInfoTo.getUserId());
			if (tempCartItems!=null){
				//临时购物车有数据，需要合并
				for (CartItem item : tempCartItems) {
					addToCart(item.getSkuId(),item.getCount());
				}
			}
			//3、获取登录后的购物车的数据【包含合并过来的临时购物车的数据，和登录后的购物车的数据】
			List<CartItem> cartItems = getCartItems(cartKey);
			cart.setItems(cartItems);
		}else {
			//2、没登录
			String cartKey = CART_PREFIX + userInfoTo.getUserKey();
			//获取临时购物车的所有购物项
			List<CartItem> cartItems = getCartItems(cartKey);
			cart.setItems(cartItems);
		}
		return cart;
	}

	@Override
	public void clearCart(String cartKey) {
		redisTemplate.delete(cartKey);
	}

	@Override
	public void checkItem(Long skuId, Integer check) {
		BoundHashOperations<String, Object, Object> cartOps = getCartOps();
		CartItem cartItem = getCartItem(skuId);
		cartItem.setCheck(check==1?true:false);
		String s = JSON.toJSONString(cartItem);
		cartOps.put(skuId.toString(),s);
	}

	@Override
	public void changeItemCount(Long skuId, Integer num) {
		CartItem cartItem = getCartItem(skuId);
		cartItem.setCount(num);

		BoundHashOperations<String, Object, Object> cartOps = getCartOps();
		cartOps.put(skuId.toString(),JSON.toJSONString(cartItem));
	}

	@Override
	public void deleteItem(Long skuId) {
		BoundHashOperations<String, Object, Object> cartOps = getCartOps();
		cartOps.delete(skuId.toString());
	}

	@Override
	public List<CartItem> getUserCartItems() {
		UserInfoTo userInfoTo = CartInterceptor.threadLocal.get();
		if (userInfoTo.getUserId()==null){
			return null;
		}else {
			String cartKey	= CART_PREFIX + userInfoTo.getUserId();
			List<CartItem> cartItems = getCartItems(cartKey);
			List<CartItem> collect = cartItems.stream().filter(	item -> item.getCheck())
					.map(item->{
						//当前购物车价格为redis缓存中的，并非为最新价格，需要查询数据库后更新为最新价格
						R price = productFeignService.getPrice(item.getSkuId());
						String data = (String) price.get("data");
						item.setPrice(new BigDecimal(data));
						return item;
					})
					.collect(Collectors.toList());
			return collect;
		}
	}

	private List<CartItem> getCartItems(String cartKey) {
		BoundHashOperations<String, Object, Object> hashOps = redisTemplate.boundHashOps(cartKey);
		List<Object> values = hashOps.values();
		if (values!=null && values.size()>0){
			List<CartItem> collect = values.stream().map((obj) -> {
				String str = (String) obj;
				CartItem cartItem = JSON.parseObject(str, CartItem.class);
				return cartItem;
			}).collect(Collectors.toList());
			return collect;
		}
		return null;
	}

	private BoundHashOperations<String, Object, Object> getCartOps() {
		UserInfoTo userInfoTo = CartInterceptor.threadLocal.get();
		String cartKey = "";
		if (userInfoTo.getUserId() != null) {
			//gulimall:cart:1
			cartKey	= CART_PREFIX + userInfoTo.getUserId();
		}	else {
			cartKey = CART_PREFIX + userInfoTo.getUserKey();
		}
		BoundHashOperations<String, Object, Object> operations = redisTemplate.boundHashOps(cartKey);

		return operations;
	}
}
